#define		_Exception_Vector	0xD0037400
#define		 pExceptionRESET	( *((volatile unsigned long *)(_Exception_Vector + 0x0)) )
#define		 pExceptionUNDEF	( *((volatile unsigned long *)(_Exception_Vector + 0x4)) )
#define		 pExceptionSWI		( *((volatile unsigned long *)(_Exception_Vector + 0x8)) )
#define 	pExceptionPABORT	( *((volatile unsigned long *)(_Exception_Vector + 0xc)) )
#define 	pExceptionDABORT	( *((volatile unsigned long *)(_Exception_Vector + 0x10)) )
#define	        pExceptionRESERVED	( *((volatile unsigned long *)(_Exception_Vector + 0x14)) )
#define		pExceptionIRQ		( *((volatile unsigned long *)(_Exception_Vector + 0x18)) )
#define		pExceptionFIQ		( *((volatile unsigned long *)(_Exception_Vector + 0x1c)) )


#define    VIC0INTENCLEAR         ( *((volatile unsigned long *)(0xF2000014)))
#define    VIC1INTENCLEAR         ( *((volatile unsigned long *)(0xF2100014)))
#define    VIC2INTENCLEAR         ( *((volatile unsigned long *)(0xF2200014)))
#define    VIC3INTENCLEAR         ( *((volatile unsigned long *)(0xF2300014)))

#define    VIC0INTSELECT         ( *((volatile unsigned long *)(0xF200000C)))
#define    VIC1INTSELECT         ( *((volatile unsigned long *)(0xF210000C)))
#define    VIC2INTSELECT         ( *((volatile unsigned long *)(0xF220000C)))
#define    VIC3INTSELECT         ( *((volatile unsigned long *)(0xF230000C)))

#define    VIC0ADDR         ( *((volatile unsigned long *)(0xF2000F00)))
#define    VIC1ADDR         ( *((volatile unsigned long *)(0xF2100F00)))
#define    VIC2ADDR         ( *((volatile unsigned long *)(0xF2200F00)))
#define    VIC3ADDR         ( *((volatile unsigned long *)(0xF2300F00)))

#define    VIC0IRQSTATUS         ( *((volatile unsigned long *)(0xF2000000)))
#define    VIC1IRQSTATUS         ( *((volatile unsigned long *)(0xF2100000)))
#define    VIC2IRQSTATUS         ( *((volatile unsigned long *)(0xF2200000)))
#define    VIC3IRQSTATUS         ( *((volatile unsigned long *)(0xF2300000)))


//#define    VIC0VECTADDR         ( *((volatile unsigned long *)(0xF2000100)))
//#define    VIC1VECTADDR         ( *((volatile unsigned long *)(0xF2100100)))
//#define    VIC2VECTADDR         ( *((volatile unsigned long *)(0xF2200100)))
//#define    VIC3VECTADDR         ( *((volatile unsigned long *)(0xF2300100)))

#define    VIC0VECTADDR         0xF2000100
#define    VIC1VECTADDR         0xF2100100
#define    VIC2VECTADDR         0xF2200100
#define    VIC3VECTADDR         0xF2300100

#define    VIC0INTENABLE         ( *((volatile unsigned long *)(0xF2000010)))
#define    VIC1INTENABLE         ( *((volatile unsigned long *)(0xF2100010)))
#define    VIC2INTENABLE         ( *((volatile unsigned long *)(0xF2200010)))
#define    VIC3INTENABLE         ( *((volatile unsigned long *)(0xF2300010)))

#define    VIC0INTCLEAR         ( *((volatile unsigned long *)(0xF2000014)))
#define    VIC1INTCLEAR         ( *((volatile unsigned long *)(0xF2100014)))
#define    VIC2INTCLEAR         ( *((volatile unsigned long *)(0xF2200014)))
#define    VIC3INTCLEAR         ( *((volatile unsigned long *)(0xF2300014)))


/*void reset_exception(void)
{
	printf("reset_exception.\n");
}
 
void undef_exception(void)
{
	printf("undef_exception.\n");
}
 
void sotf_int_exception(void)
{
	printf("sotf_int_exception.\n");
}
 
void prefetch_exception(void)
{
	printf("prefetch_exception.\n");
}
 
void data_exception(void)
{
	printf("data_exception.\n");
}*/

extern void IRQ_handler();

static inline unsigned int get_vectors_address(void)
{
    unsigned int temp;
 
    /* read SCTLR */
	
	__asm__ __volatile__(
		   "mrc p15, 0, %0, c1, c0, 0\n"
			:"=r"(temp)
			:
			
	);
	
    if (temp & (1<<13))
        return (unsigned int ) 0xffff0000;
    /* read VBAR */
    __asm__ __volatile__("mrc p15, 0, %0, c12, c0, 0\n"
            : "=r" (temp) : );
    return (unsigned int ) temp;
}


void system_initexception( void)
{
    // 设置中断向量表
    
    //unsigned int base = get_vectors_address();
    //*((volatile unsigned long *)(base + 0x18)) =(unsigned long)IRQ_handler;
 //   pExceptionUNDEF   = (unsigned long)IRQ_handler;
//    pExceptionSWI     = (unsigned long)IRQ_handler;
//    pExceptionPABORT  = (unsigned long)IRQ_handler;
//    pExceptionDABORT  = (unsigned long)IRQ_handler;
    pExceptionIRQ     = (unsigned long)IRQ_handler;
//    pExceptionFIQ     = (unsigned long)IRQ_handler;
    // 初始化中断控制器
    intc_init();

}
void intc_init()
{
    // 禁止所有中断
    VIC0INTENCLEAR = 0xffffffff;
    VIC1INTENCLEAR = 0xffffffff;
    VIC2INTENCLEAR = 0xffffffff;
    VIC3INTENCLEAR = 0xffffffff;
    // 选择中断类型为IRQ
    VIC0INTSELECT = 0x0;
    VIC1INTSELECT = 0x0;
    VIC2INTSELECT = 0x0;
    VIC3INTSELECT = 0x0;
    // 清VICxADDR
    VIC0ADDR = 0;
    VIC1ADDR = 0;
    VIC2ADDR = 0;
    VIC3ADDR = 0;
    //intc_setvectaddr(0, isr_eint0());
    //intc_setvectaddr(1, isr_eint1());
    //intc_setvectaddr(0, IRQ_handler);
    //intc_setvectaddr(1, IRQ_handler);
}


// 读取VICnIRQSTATUS寄存器，判断其中哪个为1，可知哪个VIC发生中断了
unsigned long intc_getvicirqstatus(unsigned long ucontroller)
{
    if(ucontroller ==0)
	return VIC0IRQSTATUS;
    else if(ucontroller ==1)
	return VIC1IRQSTATUS;
    else if(ucontroller ==2)
	return VIC2IRQSTATUS;
    else if(ucontroller ==3)
	return VIC3IRQSTATUS;
    else
    {}
    return 0;
}

void irq_handler(void)
{
    unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};
    int i=0;
    void (*isr)(void)=0;

    for(; i<4; i++)
    {
        if(intc_getvicirqstatus(i) != 0)
        {
            isr = (void (*)(void)) vicaddr[i];
            putc('*');
	    break;
        }
    }
    (*isr)();

}
void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
{
    if(intnum <32) {
	*((volatile unsigned long *)(VIC0VECTADDR + 4*(intnum-0)))=(int) handler;
    }
    else if(intnum <64) {
	*((volatile unsigned long *)(VIC1VECTADDR + 4*(intnum-32)))=(unsigned) handler;
    }
    else if(intnum <96) {
	*((volatile unsigned long *)(VIC2VECTADDR + 4*(intnum-64)))=(unsigned) handler;
    }
    else {
	*((volatile unsigned long *)(VIC3VECTADDR + 4*(intnum-96)))=(unsigned) handler;
    }
}
void intc_enable(unsigned long intnum)
{
    unsigned long temp;
    if(intnum<32)
    {
        temp = VIC0INTENABLE;
        temp |= (1<<intnum);
        VIC0INTENABLE = temp;
    }
    else if(intnum<64)
    {
        temp = VIC1INTENABLE;
        temp |= (1<<(intnum-32));
        VIC1INTENABLE = temp;
    }
    else if(intnum<96)
    {
        temp = VIC2INTENABLE;
        temp |= (1<<(intnum-64));
        VIC2INTENABLE = temp;
    }
    else if(intnum<127)
    {
        temp = VIC3INTENABLE;
        temp |= (1<<(intnum-96));
        VIC3INTENABLE = temp;
    }
    else
    {
        VIC0INTENABLE = 0xFFFFFFFF;
        VIC1INTENABLE = 0xFFFFFFFF;
        VIC2INTENABLE = 0xFFFFFFFF;
        VIC3INTENABLE = 0xFFFFFFFF;
    }    
}


void intc_disable(unsigned long intnum)
{
    unsigned long temp;
    if(intnum<32)
    {
        temp = VIC0INTENCLEAR;
        temp |= (1<<intnum);
        VIC0INTENCLEAR = temp;
    }
    else if(intnum<64)
    {
        temp = VIC1INTENCLEAR;
        temp |= (1<<(intnum-32));
        VIC1INTENCLEAR = temp;
    }
    else if(intnum<96)
    {
        temp = VIC2INTENCLEAR;
        temp |= (1<<(intnum-64));
        VIC2INTENCLEAR = temp;
    }
    else if(intnum<127)
    {
        temp = VIC3INTENCLEAR;
        temp |= (1<<(intnum-96));
        VIC3INTENCLEAR = temp;
    }
    else
    {
        VIC0INTENCLEAR = 0xFFFFFFFF;
        VIC1INTENCLEAR = 0xFFFFFFFF;
        VIC2INTENCLEAR = 0xFFFFFFFF;
        VIC3INTENCLEAR = 0xFFFFFFFF; 
    }    
}

// 清除需要处理的中断的中断处理函数的地址
void intc_clearvectaddr(void)
{
    // VICxADDR:当前正在处理的中断的中断处理函数的地址
    VIC0ADDR = 0;
    VIC1ADDR = 0;
    VIC2ADDR = 0;
    VIC3ADDR = 0;
}

